﻿
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Runtime.InteropServices;

namespace Common
{
    public static class ExtensionMethods
    {
        #region Variables

        #region 输入法

        private static uint WM_INPUTLANGCHANGEREQUEST = 0x0050;
        private static int HWND_BROADCAST = 0xffff;
        private static string en_US = "00000409"; //英文
        private static string cn_ZH = "00000804";
        private static uint KLF_ACTIVATE = 1;

        #endregion

        #endregion  

        #region Constructor

        #endregion

        #region Properties

        #endregion

        #region 依赖属性

        #endregion

        #region Event

        #endregion

        #region Private Methods

        [DllImport("user32.dll")]
        private static extern bool PostMessage(int hhwnd, uint msg, IntPtr wparam, IntPtr lparam);

        [DllImport("user32.dll")]
        private static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);
        [DllImport("imm32.dll")]
        private static extern IntPtr GetKeyboardLayout(int param);

        [DllImport("imm32.dll")]
        private static extern bool ImmSetConversionStatus(IntPtr hIMC, int conversion, int sentence);

        #endregion

        #region Public/Protected Methods

        public static IntPtr GetKeyboard(int param)
        {
            return GetKeyboardLayout(param);
        }

        //调用此方法时，将屏蔽中文输入法(操作系统级别，即使使用快捷键ctrl+shift也还原不回中文输入法)
        public static void ChangeUSLanguage()
        {
            PostMessage(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, LoadKeyboardLayout(en_US, KLF_ACTIVATE));
        }

        //调用此方法时，将可以使用中文输入法(中文输入法有效)
        public static void ChangeZHLanguage()
        {
            PostMessage(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, LoadKeyboardLayout(cn_ZH, KLF_ACTIVATE));
        }

        public static void SetImm(IntPtr param)
        {
            ImmSetConversionStatus(param, 1025, 0);
        }

        /// 转全角的函数(SBC case)
        ///
        ///任意字符串
        ///全角字符串
        ///
        ///全角空格为12288，半角空格为32
        ///其他字符半角(33-126)与全角(65281-65374)的对应关系是：均相差65248
        ///
        public static string ToSBC(string input)
        {
            try
            {
                // 半角转全角：
                char[] c = input.ToCharArray();
                for (int i = 0; i < c.Length; i++)
                {
                    if (c[i] == 32)
                    {
                        c[i] = (char)12288;
                        continue;
                    }
                    if (c[i] < 127)
                        c[i] = (char)(c[i] + 65248);
                }
                return new string(c);
            }
            catch (Exception ex)
            {
                LogHelper.Error("ExtensionMethods", ex);
                return input;
            }
        }

        /**/
        // /
        // / 转半角的函数(DBC case)
        // /
        // /任意字符串
        // /半角字符串
        // /
        // /全角空格为12288，半角空格为32
        // /其他字符半角(33-126)与全角(65281-65374)的对应关系是：均相差65248
        // /
        public static string ToDBC(this string input)
        {
            try
            {
                char[] c = input.ToCharArray();
                for (int i = 0; i < c.Length; i++)
                {
                    if (c[i] == 12288)
                    {
                        c[i] = (char)32;
                        continue;
                    }
                    if (c[i] > 65280 && c[i] < 65375)
                        c[i] = (char)(c[i] - 65248);
                }
                return new string(c);
            }
            catch (Exception ex)
            {
                LogHelper.Error("ExtensionMethods", ex);
                return input;
            }
        }

        /// <summary>
        /// 0:等于 1:大于 -1：小于 2:异常
        /// </summary>
        /// <returns></returns>
        public static int CompateVersion(this Version localVersion, Version serverVersion)
        {
            try
            {
                if (localVersion == serverVersion)
                {
                    return 0;
                }
                else if (localVersion >= serverVersion)
                {
                    return 1;
                }
                else
                {
                    return -1;
                }
            }
            catch (Exception ex)
            {
                return 2;
            }
        }

        public static Version CreateVersionByPreVersion(Version ver, int maxVersion)
        {
            string[] strs = ver.ToString().Split('.');
            VersionNum(strs, strs.Length - 1, maxVersion);
            string str = "";
            for (int i = 0; i < strs.Length; i++)
            {
                string temp = "";
                if (i < strs.Length - 1)
                {
                    temp = strs[i] + '.';
                }
                else
                {
                    temp = strs[i];
                }
                str += temp;
            }
            return new Version(str);
        }

        private static void VersionNum(string[] strs, int j, int maxVersion)
        {
            for (int i = j; i >= 0; i--)
            {
                int num = int.Parse(strs[i]);
                if (num >= maxVersion)
                {
                    strs[i] = "0";
                    VersionNum(strs, i, maxVersion);
                }
                else
                {
                    strs[i] = num + 1 + "";
                    break;
                }
            }
        }

        /// <summary>
        /// 把Json文本转为实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <returns></returns>
        public static T FromJSON<T>(this string input)
        {
            try
            {
                return JsonConvert.DeserializeObject<T>(input);
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }


        /// <summary>
        /// 把对象转换为JSON字符串(不带objectid)
        /// </summary>
        /// <param name="o">对象</param>
        /// <returns>JSON字符串</returns>
        public static string ObjectToJson<T>(this T obj)
        {
            if (obj == null)
            {
                return null;
            }
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// 把对象转换为JSON字符串(带objectid)
        /// </summary>
        /// <param name="o">对象</param>
        /// <returns>JSON字符串</returns>
        public static string ObjectToJsonM<T>(this T obj)
        {
            if (obj == null)
            {
                return null;
            }
            return obj.ToJson();
        }


        /// <summary>
        /// 把Json文本转为实体(不带objectid)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <returns></returns>
        public static T JsonToObject<T>(this string jsonString)
        {
            try
            {
                T o = JsonConvert.DeserializeObject<T>(jsonString);
                return o;
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }

        /// <summary>
        /// 把Json文本转为实体(带objectid)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <returns></returns>
        public static T JsonToObjectM<T>(this string jsonString)
        {
            try
            {
                if (string.IsNullOrEmpty(jsonString))
                {
                    return default(T);
                }
                T o = BsonSerializer.Deserialize<T>(jsonString);
                return o;
            }
            catch (Exception)
            {
                return default(T);
            }
        }

        public static T CloneObj<T>(this T obj)
        {
            if (obj == null)
            {
                return default(T);
            }
            else
            {
                string json = ObjectToJsonM(obj);
                T newObj = JsonToObjectM<T>(json);
                return newObj;
            }
        }

        public static object GetValueByPropertyName<T>(this T obj, string propertyName)
        {
            string[] names = propertyName.Split('.');
            object temp = obj;
            foreach (var item in names)
            {
                if (!string.IsNullOrEmpty(item))
                {
                    temp = temp.GetType().GetProperty(item).GetValue(obj);
                }
            }
            return temp;
        }

        public static void SetValueByPropertyName<T>(this T obj, string propertyName, object value)
        {
            string[] names = propertyName.Split('.');
            IEnumerable<string> list = names.Where(O => !string.IsNullOrEmpty(O));
            object temp = obj;
            for (int i = 0; i < list.Count(); i++)
            {
                string item = names[i];
                if (i == names.Length - 1)
                {
                    temp.GetType().GetProperty(item).SetValue(temp, value);
                }
                else
                {
                    temp = temp.GetType().GetProperty(item).GetValue(obj);
                }
            }
        }

        public static ObservableCollection<T> ToObservableCollection<T>(this IList<T> list)
        {
            try
            {
                ObservableCollection<T> observableCollection = new ObservableCollection<T>();
                foreach (var item in list)
                {
                    observableCollection.Add(item);
                }

                return observableCollection;
            }
            catch (Exception)
            {
                return null;
            }
        }
        public static double ToDouble(this string s)
        {
            if (string.IsNullOrEmpty(s)) return 0;
            if (s.isNumberic())
                return Math.Round(double.Parse(s), 2);
            else
                return 0;
        }

        public static bool isNumberic(this string message)
        {
            Regex rex = new Regex("^(-?[0-9]+[.]?[0-9]*)$");
            if (rex.IsMatch(message))
                return true;
            else
                return false;
        }
        //正则匹配 

        // 数字应该有正数和负数，正确的正则表达式为： "^(-?[0-9]+[.]?[0-9]*)$"
        //1、^文本的开头，为空
        //2、$文本的结尾，为空
        //3、中间全部用括号括起来
        //4、-?，表示负号可有可无
        //5、[0-9]+，表示0至9的数字至少出现一次，而不能是[0 - 9]*,这样就会出现错误，如果用户只输入了一个负号，后边什么也没有输入，肯定要出错，但如果输入“-006789”,那也是-6789
        //6、[.]?，表示小数点可有可无
        //7、[0-9]*，表示小数点后可以有苦干位小数

        //匹配中文字符的正则表达式： [\u4e00-\u9fa5]
        //匹配双字节字符(包括汉字在内)：[^\x00-\xff]
        //匹配空行的正则表达式：\n[\s | ]*\r
        //匹配HTML标记的正则表达式：/<(.*)>.*<\/\1>|<(.*) \/>/ 
        //匹配首尾空格的正则表达式：(^\s*)|(\s*$)（像vbscript那样的trim函数） 
        //匹配Email地址的正则表达式：\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 
        //匹配网址URL的正则表达式：http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)? 
        //以下是例子： 
        //利用正则表达式限制网页表单里的文本框输入内容： 
        //用正则表达式限制只能输入中文：onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" 
        //onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"

        //1.用正则表达式限制只能输入全角字符： onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" 
        //onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"

        //2.用正则表达式限制只能输入数字：onkeyup="value=value.replace(/[^\d]/g,'') 
        //"onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

        //3.用正则表达式限制只能输入数字和英文：onkeyup="value=value.replace(/[\W]/g,'') 
        //"onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"


        public static string GetProperties<T>(T t)
        {
            string tStr = string.Empty;
            if (t == null)
            {
                return tStr;
            }

            System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);

            if (properties.Length <= 0)
            {
                return tStr;
            }
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                string name = item.Name;
                object value = item.GetValue(t, null);
                if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
                {
                    tStr += string.Format("{0}:{1},", name, value);
                    bool b = SetModelValue(name, value, t);
                }
                else
                {
                    GetProperties(value);
                }
            }
            return tStr;
        }

        /// 
        /// 设置类中的属性值
        /// 
        /// 
        /// 
        /// 
        public static bool SetModelValue(this string FieldName, object Value, object obj)
        {
            try
            {
                Type Ts = obj.GetType();
                object v = Convert.ChangeType(Value, Ts.GetProperty(FieldName).PropertyType);
                Ts.GetProperty(FieldName).SetValue(obj, v, null);
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// 
        /// 获取类中的属性值
        /// 
        /// 
        /// 
        /// 
        public static string GetModelValue(string FieldName, object obj)
        {
            try
            {
                Type Ts = obj.GetType();
                object o = Ts.GetProperty(FieldName).GetValue(obj, null);
                string Value = Convert.ToString(o);
                if (string.IsNullOrEmpty(Value)) return null;
                return Value;
            }
            catch
            {
                return null;
            }
        }


        /// <summary>
        /// 32位MD5加密
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string MD5Encrypt32(this string password)
        {
            //string cl = password;
            //string pwd = "";
            //MD5 md5 = MD5.Create(); //实例化一个md5对像
            //                        // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　
            //byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
            //// 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得
            //for (int i = 0; i < s.Length; i++)
            //{
            //    // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符 
            //    pwd = pwd + s[i].ToString("X");
            //}
            //return pwd;


            string cl = password;
            if (!string.IsNullOrEmpty(cl))
            {
                try
                {
                    MD5 md5 = MD5.Create(); //实例化一个md5对像
                    byte[] results = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
                    string resultString = byteArrayToHexString(results);
                    return resultString.ToUpper();
                }
                catch (Exception ex)
                {
                }
            }
            return null;
        }

        private static string byteArrayToHexString(byte[] b)
        {
            StringBuilder resultSb = new StringBuilder();
            foreach (var element in b)
            {
                resultSb.Append(byteToHexString(element));
            }
            return resultSb.ToString();
        }

        private static string byteToHexString(byte b)
        {
            int n = b;
            if (n < 0)
            {
                n = 256 + n;
            }
            int d1 = n / 16;
            int d2 = n % 16;
            return HEXDIGITS[d1] + HEXDIGITS[d2];
        }

        private static String[] HEXDIGITS = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

        #region IEnumerable接口的扩展方法，支持它的实现类是List的情况

        public static void Add<T>(this IEnumerable<T> collection, T value)
        {
            (collection as List<T>).Add(value);
        }
        /// <summary>
        /// 从集合中删除元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="value"></param>
        public static void Remove<T>(this IEnumerable<T> collection, T value)
        {
            (collection as List<T>).Remove(value);
        }
        ///// <summary>
        ///// 检索集合中是否包含某个元素
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="collection"></param>
        ///// <param name="value"></param>
        ///// <returns></returns>
        //public static bool Contains<T>(this IEnumerable<T> collection, T value)
        //{
        //    return (collection as List<T>).Contains(value);
        //}

        /// <summary>
        /// 清空集合元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static void Clear<T>(this IEnumerable<T> collection)
        {
            if ((collection as List<T>) != null)
                (collection as List<T>).Clear();
        }

        #endregion

        #endregion

        #region EventHandlers

        #endregion

    }
}
